import { toast } from "sonner";
import { memo, useCallback, useId, useState } from "react";
import { TextField, Tooltip, Button, ButtonGroup } from "@mui/material";
import { IResponseMessage, Message } from "@/lib/types";
import MarkdownMessage from "../MarkdownMessage";
import highlightElement from "@/lib/utils/highlightElement";
import LikeIcon from "@/assets/icons/like.svg?jsx";
import DislikeIcon from "@/assets/icons/dislike.svg?jsx";
import ClipboardIcon from "@/assets/icons/clipboard.svg?jsx";
import RegenerateIcon from "@/assets/icons/cycle.svg?jsx";
import GPTIcon from "@/assets/images/gpt.png";
import Collapse from "../Collapse";

type ResponseMessageProps = {
  message: Message<IResponseMessage>;
  onClickRecommend: (prompt: string) => void;
  onSendFeedback: (
    rating: 0 | 1,
    text: string,
    message: Message<IResponseMessage>,
  ) => Promise<void>;
  onRegenerate: (parent: string) => void;
};

export default memo(ResponseMessage);

function ResponseMessage(props: ResponseMessageProps) {
  const { message, onClickRecommend, onSendFeedback, onRegenerate } = props;
  const [feedback, setFeedback] = useState<{ rating?: 0 | 1; open: boolean }>({
    rating: undefined,
    open: false,
  });
  const randomId = useId();
  const handleClickSourceCitation = useCallback(
    (index: number) => {
      const target = document.getElementById(randomId + index);
      if (!target) {
        return;
      }
      highlightElement(target);
    },
    [randomId],
  );

  return (
    <div className="flex w-full gap-x-4 [&:not(:first-child)]:mt-4">
      <div className="flex-none">
        <img src={GPTIcon} alt="" className="size-6" />
      </div>
      <div className="flex-auto self-start rounded-lg bg-[#363A48] p-5">
        <MarkdownMessage
          onClickSourceCitation={handleClickSourceCitation}
          markdown={
            message.message.content +
            (message.message.done
              ? ""
              : "<span style='background-color: #eee;'>&nbsp;</span>")
          }
        />
        <Actions
          message={message.message}
          onClickFeedback={(rating) => setFeedback({ rating, open: true })}
          onRegenerate={() => onRegenerate(message.parent!)}
        />
        {message.message.error && (
          <div className="mt-4 rounded border border-red-400/80 bg-red-300/20 p-4 text-sm">
            生成错误：{message.message.error.message}
          </div>
        )}
        {feedback.open && (
          <Feedback
            rating={feedback.rating}
            onCancel={() => setFeedback({ open: false, rating: undefined })}
            onSubmit={(text) =>
              onSendFeedback(feedback.rating!, text, message)
                .then(() => setFeedback({ open: false, rating: undefined }))
                .catch(() => {
                  toast.error("提交失败！");
                })
            }
          />
        )}
        <Sources idPrefix={randomId} message={message.message} />
        <Recommend
          message={message.message}
          onClickRecommend={onClickRecommend}
        />
      </div>
    </div>
  );
}

type ActionProps = {
  message: IResponseMessage;
  onClickFeedback: (rating: 0 | 1) => void;
  onRegenerate: () => void;
};
function Actions(props: ActionProps) {
  const { message, onClickFeedback, onRegenerate } = props;
  const { done, error } = message;

  if (done === false || message.id === "preset-assistant-message") {
    return null;
  }

  const isError = !!error;

  return (
    <div className="mt-3 flex justify-end gap-x-2">
      <ButtonGroup
        variant="text"
        size="small"
        sx={{
          "& .MuiButtonGroup-firstButton": { border: "none" },
          "& .MuiButtonGroup-middleButton": { border: "none" },
        }}
      >
        {!isError && (
          <>
            <Tooltip title="感觉不错😀">
              <Button onClick={() => onClickFeedback(0)}>
                <LikeIcon height={16} width={16} />
              </Button>
            </Tooltip>
            <Tooltip title="感觉不行😥">
              <Button onClick={() => onClickFeedback(1)}>
                <DislikeIcon height={16} width={16} />
              </Button>
            </Tooltip>
          </>
        )}
        <Tooltip title="重新生成">
          <Button onClick={onRegenerate}>
            <RegenerateIcon height={16} width={16} />
          </Button>
        </Tooltip>
        <Tooltip title="复制">
          <Button
            onClick={() => {
              navigator.clipboard.writeText(message.content);
            }}
          >
            <ClipboardIcon height={16} width={16} />
          </Button>
        </Tooltip>
      </ButtonGroup>
    </div>
  );
}

type FeedbackProps = {
  rating?: 0 | 1;
  onCancel: () => void;
  onSubmit: (text: string) => Promise<any>;
};
function Feedback(props: FeedbackProps) {
  const { rating, onCancel, onSubmit } = props;
  const [isPending, setPending] = useState(false);
  const [input, setInput] = useState("");

  const handleSubmit = useCallback(async () => {
    if (isPending) {
      return;
    }
    setPending(true);
    await onSubmit(input);
    setPending(false);
  }, [isPending, onSubmit, input]);

  return (
    <div className="mt-4">
      <div className="mb-2 text-sm">
        {rating === 0 ? "请告诉我们更多的细节" : "告诉我们哪里做的不够好"}
      </div>
      <TextField
        multiline
        fullWidth
        value={input}
        onInput={(e) => setInput((e.target as HTMLTextAreaElement).value)}
        variant="standard"
        minRows={2}
        maxRows={4}
        InputProps={{
          disableUnderline: true,
        }}
      />
      <div className="mt-2 flex justify-end">
        <Button size="small" onClick={onCancel} variant="text">
          取消
        </Button>
        <Button size="small" onClick={handleSubmit} variant="contained">
          提交
        </Button>
      </div>
    </div>
  );
}

function Sources({
  message,
  idPrefix,
}: {
  message: IResponseMessage;
  idPrefix: string;
}) {
  const { source } = message;
  if (source.length === 0) {
    return null;
  }

  return (
    <div className="mt-4 text-sm">
      <Collapse title="来源">
        <ul className="list-decimal pl-4">
          {source.map((item, index) => (
            <li key={index}>
              <a
                id={idPrefix + (index + 1)}
                href={item.url}
                target="_blank"
                className="hover:underline [&:not(:last-child)]:mr-2"
              >
                {item.title}
              </a>
            </li>
          ))}
        </ul>
      </Collapse>
    </div>
  );
}

function Recommend({
  message,
  onClickRecommend,
}: {
  message: IResponseMessage;
  onClickRecommend: (prompt: string) => void;
}) {
  const { recommend } = message;
  if (recommend.length === 0) {
    return null;
  }

  return (
    <div className="mt-4 text-sm">
      <p className="mb-1">您可以问我：</p>
      <ol className="list-decimal pl-4">
        {recommend.map((item, index) => (
          <li
            key={index}
            className="cursor-pointer"
            onClick={() => onClickRecommend(item)}
          >
            {item}
          </li>
        ))}
      </ol>
    </div>
  );
}
